package com.bite.user.service.impl;


import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.bite.blog.api.BlogServiceApi;
import com.bite.common.constant.Constant;
import com.bite.common.exception.BlogException;
import com.bite.blog.api.pojo.BlogInfoResponse;
import com.bite.common.utils.*;

import com.bite.user.api.pojo.UserInfoRequest;
import com.bite.user.api.pojo.UserInfoResponse;
import com.bite.user.api.pojo.UserLoginResponse;
import com.bite.user.api.pojo.UserRegisterRequest;
import com.bite.user.convert.BeanConvert;
import com.bite.user.dataobject.UserInfo;
import com.bite.user.mapper.UserInfoMapper;
import com.bite.user.model.EmailUser;
import com.bite.user.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.HashMap;
import java.util.Map;

@Service
@Slf4j
public class UserServiceImpl implements UserService {
    @Autowired
    private RabbitTemplate rabbitTemplate;

    // 过期时间为2周
    private static final long TIME_OUT = 14 * 24 * 3600;
    @Autowired
    private UserInfoMapper userInfoMapper;
    @Autowired
    private BlogServiceApi blogServiceApi;

    @Autowired
    private RedisClient redisClient;

    // redis用户前缀
    private static final String REDIS_PREFIX = "user";


    // 创建 redis key
    private String buildKey(String userName) {
        return redisClient.buildKey(REDIS_PREFIX, userName);
    }

    @Override
    public UserLoginResponse login(UserInfoRequest user) {
        //验证账号密码是否正确
        UserInfo userInfo = queryUserInfo(user.getUserName());
        if (userInfo==null || userInfo.getId()==null){
            throw new BlogException("用户不存在");
        }
//        if (!user.getPassword().equals(userInfo.getPassword())){
//            throw new BlogException("用户密码不正确");
//        }
        if (!SecurityUtil.verify(user.getPassword(),userInfo.getPassword())){
            throw new BlogException("用户密码不正确");
        }
        //账号密码正确的逻辑
        Map<String,Object> claims = new HashMap<>();
        claims.put("id", userInfo.getId());
        claims.put("name", userInfo.getUserName());

        String jwt = JWTUtils.genJwt(claims);
        return new UserLoginResponse(userInfo.getId(), jwt);
    }

    @Override
    public UserInfoResponse getUserInfo(Integer userId) {
        UserInfoResponse userInfoResponse = new UserInfoResponse();
        UserInfo userInfo = selectUserInfoById(userId);
        BeanUtils.copyProperties(userInfo, userInfoResponse);
        return userInfoResponse;
    }

    @Override
    public UserInfoResponse selectAuthorInfoByBlogId(Integer blogId) {
        UserInfoResponse userInfoResponse = new UserInfoResponse();
        //1. 根据博客ID, 获取作者ID
        BlogInfoResponse blogInfo = blogServiceApi.getBlogDetail(blogId).getData();
        //2. 根据作者ID, 获取作者信息
        if (blogInfo == null){
            throw new BlogException("博客不存在");
        }
        UserInfo userInfo = selectUserInfoById(blogInfo.getUserId());
        BeanUtils.copyProperties(userInfo, userInfoResponse);
        return userInfoResponse;
    }

    /**
     * 注册
     */
    @Override
    public Integer register(UserRegisterRequest registerRequest) {
        // 校验
        checkRegisterInfo(registerRequest);
        // 转换
        UserInfo userInfo = BeanConvert.registerConvertByEncrypt(registerRequest);
        try {
            // 注册（插入）
            int insert = userInfoMapper.insert(userInfo);

            if (insert == 1) {
                // 插入成功
                // 将数据添加到redis中
                String userJSON = JsonUtils.toJson(userInfo);
                redisClient.set(buildKey(userInfo.getUserName()), userJSON, TIME_OUT);

                // 转化为 EmailUser
                EmailUser emailUser = EmailUser.build(userInfo);
                // 发送到MQ消息队列
                rabbitTemplate.convertAndSend(Constant.USER_EXCHANGE_NAME, "", JsonUtils.toJson(emailUser));

                return userInfo.getId();
            } else {
                throw new BlogException("用户注册失败");
            }

        } catch (Exception e) {
            // 由于就算在redis中找不到用户数据也可以在MySQL中寻找 所以就不处理Redis失败时候的异常了
            log.error("用户注册失败 e: {}", e.toString());
            throw new BlogException("用户注册失败");
        }
    }

    private void checkRegisterInfo(UserRegisterRequest param) {
        // 用户名是否重复
        UserInfo userInfo = queryUserInfo(param.getUserName());
        if (userInfo != null) {
            throw new BlogException("用户名已经被注册");
        }

        // 验证邮箱和url
        if (StringUtils.hasLength(param.getEmail()) && !RegexUtil.checkMail(param.getEmail())) {
            throw new BlogException("邮箱格式错误");
        }
        if (StringUtils.hasLength(param.getGithubUrl()) && !RegexUtil.checkURL(param.getGithubUrl())) {
            throw new BlogException("github 格式错误");
        }
    }

    private UserInfo queryUserInfo(String userName) {
        String key = buildKey(userName);
        if (redisClient.exists(key)) {
            log.info("从Redis中获取用户信息 key: {}", key);
            // redis 获取
            UserInfo userInfo = JsonUtils.parseJson(redisClient.get(key), UserInfo.class);
            if (userInfo == null) {
                log.warn("queryUserInfo redis 获取失败 key {}", key);
                // 获取失败 那么就去mysql中获取
                return selectUserInfoByName(userName);
            } else {
                return userInfo;
            }
        } else {
            // mysql 中获取 并存储到redis
            UserInfo userInfo = selectUserInfoByName(userName);
            redisClient.set(key, JsonUtils.toJson(userInfo));
            return userInfo;
        }
    }


    public UserInfo selectUserInfoByName(String userName) {
        return userInfoMapper.selectOne(new LambdaQueryWrapper<UserInfo>()
                .eq(UserInfo::getUserName, userName).eq(UserInfo::getDeleteFlag, 0));
    }
    private UserInfo selectUserInfoById(Integer userId) {
        return userInfoMapper.selectOne(new LambdaQueryWrapper<UserInfo>()
                .eq(UserInfo::getId, userId).eq(UserInfo::getDeleteFlag, 0));
    }
}
